package main

import (
	"crypto/ecdsa"
	"crypto/rand"
	"crypto/sha256"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"math/big"
	"time"
)

type Sign struct {
	r *big.Int
	s *big.Int
}
/**
ecc私钥签名
 */
func eccSigData(privatefilePath string, text []byte) (Sign,error) {
	// 读取私钥内容
	info, err := ioutil.ReadFile(privatefilePath)
	if err != nil {
		fmt.Println("1:",err)
		return Sign{},err
	}
	//得到pem的block
	block,_:=pem.Decode(info)
	// 解密私钥 得到私钥
	/**
	func ParseECPrivateKey
	func ParseECPrivateKey(der []byte) (key *ecdsa.PrivateKey, err error)
	ParseECPrivateKey解析ASN.1 DER编码的ecdsa私钥。
	 */
	privateKey,err:=x509.ParseECPrivateKey(block.Bytes)
	if err != nil {
		return Sign{},err
	}
	// 对原文hash
	hash:=sha256.Sum256(text)
	// 对hash签名
	/**
	func Sign
	func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error)
	使用私钥对任意长度的hash值（必须是较大信息的hash结果）进行签名，返回签名结果（一对大整数）。私钥的安全性取决于密码读取器的熵度（随机程度）。
	 */
	r, s ,err:=ecdsa.Sign(rand.Reader,privateKey,hash[:])
	if err != nil {
		return Sign{},err
	}
	sign:=Sign{
		r: r,
		s: s,
	}

	return sign,nil
}
/**
公钥验证签名
 */
func verEccSigData(publicfilePath string,text []byte,sign Sign) (bool,error) {
	// 读取公钥内容
	info, err := ioutil.ReadFile(publicfilePath)
	if err != nil {
		fmt.Println("1:",err)
		return false,err
	}
	//得到pem的block
	block,_:=pem.Decode(info)
	// 解密公钥block 得到公钥内容
	pub,err:=x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		fmt.Println(err)
		return false,err
	}
	//由于得到的是接口，不知类型所有要进行，类型断言 得到公钥
	publicKey,ok:=pub.(*ecdsa.PublicKey)
	if !ok {
		fmt.Println(`类型断言失败`)
		return false,err
	}
	
	hash:=sha256.Sum256(text)
	/** 进行验证
	func Verify
	func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool
	使用公钥验证hash值和两个大整数r、s构成的签名，并返回签名是否合法。
	 */
	isok:=ecdsa.Verify(publicKey,hash[:],sign.r,sign.s)
	if !isok {
		return false,err
	}
	return true,err
}

func main() {
	sign,err:=eccSigData(`./privateEccKey.pem`,[]byte(`你是谁，那我是谁？`))
	if err != nil {
		fmt.Println("错误：",err)
		return
	}
	fmt.Println("正确得到：")
	fmt.Println("ign.s：",sign.s)
	fmt.Println("sign.r：",sign.r)

	fmt.Println(`+++++++++++++++++++++++++++++++++++++++++++++++++++`)
	time.Sleep(time.Second*5)
	isok,err:=verEccSigData(`./publicEccKey.pem`,[]byte(`你是谁，那我是谁？`),sign)
	if err != nil {
		fmt.Println("错误：",err)
		return
	}
	fmt.Println("是否内容为被修改：",isok)
}
